#pragma once

#include "xict_common/log/log.h"
#include <map>
#include <memory>
#include <string>
#include <vector>

namespace xict_common {
    namespace utils {
        /// \brief A class that can hold any type of value.
        /// \details This class provides a way to store any type of value in
        /// a single object. It uses type erasure to achieve this. The
        /// stored value can be retrieved using the AnyCast method.
        class Any {
        public:
            /// \brief Constructs a new Any object.
            Any() : content_(nullptr) { }
            /// \brief Constructs a new Any object with the specified value.
            template <typename ValueType>
            explicit Any(const ValueType& value)
                : content_(new Holder<ValueType>(value)) { }
            /// \brief Constructs a new Any object with the same value as
            /// the specified Any object.
            Any(const Any& other)
                : content_(other.content_ ? other.content_->Clone() : nullptr) {
            }
            /// \brief Destroys the Any object.
            ~Any() {
                delete content_;
            }

            /// \brief Returns a pointer to the stored value if it is of the
            /// specified type. \tparam ValueType The type of the value to
            /// retrieve. \return ValueType* A pointer to the stored value
            /// if it is of the specified type, otherwise nullptr.
            template <typename ValueType> ValueType* AnyCast() {
                return content_
                           ? &(static_cast<Holder<ValueType>*>(content_)->held_)
                           : nullptr;
            }

        private:
            /// \brief A placeholder class for registering objects with a
            /// factory. \details This class is used as a base class for
            /// registering objects with a factory. It provides a virtual
            /// destructor and a virtual Clone() method that must be
            /// implemented by derived classes.
            class PlaceHolder {
            public:
                /// \brief Constructs a new PlaceHolder object.
                virtual ~PlaceHolder() { }
                /// \brief Clones the object.
                virtual PlaceHolder* Clone() const = 0;
            };

            /// \brief A concrete implementation of the PlaceHolder
            /// interface that holds a value of type ValueType. \tparam
            /// ValueType The type of the value to be held.
            template <typename ValueType> class Holder : public PlaceHolder {
            public:
                /// \brief Constructs a new Holder object with the given
                /// value. \param value The value to be held by the Holder
                /// object.
                explicit Holder(const ValueType& value) : held_(value) { }

                /// \brief Destroys the Holder object.
                virtual ~Holder() { }

                /// \brief Creates a new Holder object that is a copy of
                /// this object. \return A new Holder object that is a copy
                /// of this object.
                PlaceHolder* Clone() const override {
                    return new Holder(held_);
                }

                /// \brief The value held by the Holder object.
                ValueType held_;
            };

            /// \brief A pointer to the PlaceHolder object that holds the
            /// value.
            PlaceHolder* content_;
        };

        using AnyPtr      = std::shared_ptr<Any>;
        using AnyConstPtr = std::shared_ptr<const Any>;

        /// \brief A factory class for creating objects of a certain type.
        /// \details This class provides a way to create objects of a
        /// certain type without knowing the concrete implementation of the
        /// object. It is used in conjunction with the Registerer class to
        /// allow for dynamic creation of objects at runtime.
        class ObjectFactory {
        public:
            /// \brief Constructs a new ObjectFactory object.
            ObjectFactory() = default;
            /// \brief Destroys the ObjectFactory object.
            virtual ~ObjectFactory() = default;
            /// \brief Creates a new object of the type that the factory is
            /// registered for.
            virtual Any NewInstance() {
                return {};
            }
            /// \brief Deleted copy constructor.
            ObjectFactory(const ObjectFactory&) = delete;
            /// \brief Deleted copy assignment operator.
            ObjectFactory& operator=(const ObjectFactory&) = delete;
        };

        using FactoryMap   = std::map<std::string, ObjectFactory*>;
        using BaseClassMap = std::map<std::string, FactoryMap>;

        /// \brief Returns a reference to the global factory map, which maps
        /// base class types to their corresponding factory functions.
        /// \return A reference to the global factory map.
        BaseClassMap& GlobalFactoryMap();

        /// \brief Retrieves the names of all classes that are derived from
        /// the specified base class. \param base_class_name The name of the
        /// base class. \param registered_derived_classes_names A pointer to
        /// a vector that will be populated with the names of the derived
        /// classes. \return true if the operation was successful, false
        /// otherwise.
        bool GetRegisteredClasses(
            const std::string& base_class_name,
            std::vector<std::string>* registered_derived_classes_names);

/// \brief Macro to create a registerer class for a base class.
#define ZETTON_REGISTER_REGISTERER(base_class_namespace, base_class_name)     \
    class base_class_name##Registerer {                                       \
        using Any        = ::xict_common::utils::Any;                         \
        using FactoryMap = ::xict_common::utils::FactoryMap;                  \
                                                                              \
    public:                                                                   \
        static base_class_namespace::base_class_name*                         \
        GetInstanceByName(const ::std::string& name) {                        \
            FactoryMap& map =                                                 \
                ::xict_common::utils::GlobalFactoryMap()[#base_class_name];   \
            auto iter = map.find(name);                                       \
            if (iter == map.end()) {                                          \
                for (const auto& c : map) {                                   \
                    AERROR << "Instance:" << c.first;                         \
                }                                                             \
                AERROR << "Get instance " << name << " failed.";              \
                return nullptr;                                               \
            }                                                                 \
            Any object = iter->second->NewInstance();                         \
            return *(                                                         \
                object.AnyCast<base_class_namespace::base_class_name*>());    \
        }                                                                     \
        static std::vector<base_class_namespace::base_class_name*>            \
        GetAllInstances() {                                                   \
            std::vector<base_class_namespace::base_class_name*> instances;    \
            FactoryMap& map =                                                 \
                ::xict_common::utils::GlobalFactoryMap()[#base_class_name];   \
            instances.reserve(map.size());                                    \
            for (auto item : map) {                                           \
                Any object = item.second->NewInstance();                      \
                instances.push_back(*(                                        \
                    object                                                    \
                        .AnyCast<base_class_namespace::base_class_name*>())); \
            }                                                                 \
            return instances;                                                 \
        }                                                                     \
        static const ::std::string GetUniqInstanceName() {                    \
            FactoryMap& map =                                                 \
                ::xict_common::utils::GlobalFactoryMap()[#base_class_name];   \
            CHECK_EQ_S(map.size(), 1) << map.size();                          \
            return map.begin()->first;                                        \
        }                                                                     \
        static base_class_namespace::base_class_name* GetUniqInstance() {     \
            FactoryMap& map =                                                 \
                ::xict_common::utils::GlobalFactoryMap()[#base_class_name];   \
            CHECK_EQ_S(map.size(), 1) << map.size();                          \
            Any object = map.begin()->second->NewInstance();                  \
            return *(                                                         \
                object.AnyCast<base_class_namespace::base_class_name*>());    \
        }                                                                     \
        static bool IsValid(const ::std::string& name) {                      \
            FactoryMap& map =                                                 \
                ::xict_common::utils::GlobalFactoryMap()[#base_class_name];   \
            return map.find(name) != map.end();                               \
        }                                                                     \
    };

/// \brief Macro to register a class with a factory.
#define ZETTON_REGISTER_CLASS(base_class_name, class_namespace, class_name)  \
    namespace {                                                              \
        class ObjectFactory##class_name                                      \
            : public xict_common::utils::ObjectFactory {                     \
        public:                                                              \
            virtual ~ObjectFactory##class_name() { }                         \
            virtual ::xict_common::utils::Any NewInstance() {                \
                return ::xict_common::utils::Any(                            \
                    new class_namespace::class_name());                      \
            }                                                                \
        };                                                                   \
        __attribute__((constructor)) void RegisterFactory##class_name() {    \
            ::xict_common::utils::FactoryMap& map =                          \
                ::xict_common::utils::GlobalFactoryMap()[#base_class_name];  \
            if (map.find(#class_name) == map.end()) {                        \
                ADEBUG_F("Register class [{}] to factory [{}]", #class_name, \
                         #base_class_name);                                  \
                map[#class_name] =                                           \
                    new class_namespace::ObjectFactory##class_name();        \
            }                                                                \
        }                                                                    \
    }   // namespace
    }   // namespace utils
}   // namespace xict_common